import gradio as gr
import yfinance as yf
import pandas as pd
import numpy as np
import plotly.graph_objects as go
import plotly.express as px
from datetime import datetime, timedelta
from stock_database import get_stock_database

# Utility functions
def format_large_number(num):
    """Format large numbers for display"""
    if not isinstance(num, (int, float)) or pd.isna(num):
        return 'N/A'
    
    if num >= 1e9:
        return f"₹{num/1e9:.2f}B"
    elif num >= 1e7:
        return f"₹{num/1e7:.2f}Cr"
    elif num >= 1e5:
        return f"₹{num/1e5:.2f}L"
    elif num >= 1e3:
        return f"₹{num/1e3:.2f}K"
    else:
        return f"₹{num:.2f}"

def get_stock_data(ticker, period="6mo", interval="1d"):
    """Fetch stock data from Yahoo Finance"""
    try:
        stock = yf.Ticker(ticker)
        data = stock.history(period=period, interval=interval)
        
        # Get company info
        info = stock.info
        
        # Create summary metrics
        metrics = {
            'Current Price': info.get('currentPrice', info.get('regularMarketPrice', 'N/A')),
            'Market Cap': info.get('marketCap', 'N/A'),
            'PE Ratio': info.get('trailingPE', 'N/A'),
            'Dividend Yield': info.get('dividendYield', 'N/A'),
            '52 Week High': info.get('fiftyTwoWeekHigh', 'N/A'),
            '52 Week Low': info.get('fiftyTwoWeekLow', 'N/A'),
            'Volume': info.get('volume', 'N/A'),
            'Average Volume': info.get('averageVolume', 'N/A'),
            'Beta': info.get('beta', 'N/A'),
            'EPS': info.get('trailingEps', 'N/A')
        }
        
        return {
            'history': data,
            'metrics': metrics,
            'info': info
        }
    except Exception as e:
        raise Exception(f"Error fetching data: {str(e)}")

def get_dividends_splits(ticker):
    """Get dividends and splits data"""
    try:
        stock = yf.Ticker(ticker)
        dividends = stock.dividends.reset_index()
        splits = stock.splits.reset_index()
        
        # Format the dataframes
        if not dividends.empty:
            dividends.columns = ['Date', 'Dividend']
            dividends['Date'] = dividends['Date'].dt.date
        
        if not splits.empty:
            splits.columns = ['Date', 'Split']
            splits['Date'] = splits['Date'].dt.date
            splits['Split'] = splits['Split'].apply(lambda x: f"{x:.2f}:1" if x > 1 else f"1:{1/x:.2f}")
        
        return dividends, splits
    except:
        return pd.DataFrame(), pd.DataFrame()

def calculate_technical_indicators(df):
    """Calculate technical indicators for the stock data"""
    if df.empty:
        return df
    
    # Moving Averages
    df['MA20'] = df['Close'].rolling(window=20).mean()
    df['MA50'] = df['Close'].rolling(window=50).mean()
    df['MA200'] = df['Close'].rolling(window=200).mean()
    
    # Bollinger Bands
    df['Upper_Band'] = df['MA20'] + (df['Close'].rolling(window=20).std() * 2)
    df['Lower_Band'] = df['MA20'] - (df['Close'].rolling(window=20).std() * 2)
    
    # RSI (Relative Strength Index)
    delta = df['Close'].diff()
    gain = delta.where(delta > 0, 0).rolling(window=14).mean()
    loss = -delta.where(delta < 0, 0).rolling(window=14).mean()
    rs = gain / loss
    df['RSI'] = 100 - (100 / (1 + rs))
    
    # MACD (Moving Average Convergence Divergence)
    df['EMA12'] = df['Close'].ewm(span=12, adjust=False).mean()
    df['EMA26'] = df['Close'].ewm(span=26, adjust=False).mean()
    df['MACD'] = df['EMA12'] - df['EMA26']
    df['Signal_Line'] = df['MACD'].ewm(span=9, adjust=False).mean()
    df['MACD_Histogram'] = df['MACD'] - df['Signal_Line']
    
    return df

def evaluate_stock(df):
    """Simple stock evaluation based on price relative to mean and standard deviation"""
    if df.empty:
        return "No data available"
    
    recent_close = df['Close'].iloc[-1]
    avg_close = df['Close'].mean()
    std_dev = df['Close'].std()
    
    if recent_close > avg_close + std_dev:
        return "🔴 Overvalued - The stock price is significantly above its average. Consider market trends and financial reports before investing."
    elif recent_close < avg_close - std_dev:
        return "🟢 Undervalued - The stock price is significantly below its average. If the company has strong future prospects, this could be a good buying opportunity."
    else:
        return "🟡 Fairly Valued - The stock price is within a reasonable range. Check future growth prospects and company fundamentals before making a decision."

# Single Stock Analysis Function
def single_stock_analysis(stock_symbol, stock_name, period, interval):
    """Detailed analysis for a single stock"""
    try:
        # Get stock data
        data = get_stock_data(stock_symbol, period, interval)
        df = data['history']
        info = data['info']
        metrics = data['metrics']
        
        # Get dividends and splits
        dividends, splits = get_dividends_splits(stock_symbol)
        
        # Calculate technical indicators
        df_with_indicators = calculate_technical_indicators(df.copy())
        
        # Company overview
        company_overview = info.get('longBusinessSummary', 'No company description available.')
        
        # Format key metrics
        formatted_metrics = {
            "Current Price": format_large_number(metrics['Current Price']),
            "Market Cap": format_large_number(metrics['Market Cap']),
            "P/E Ratio": f"{metrics['PE Ratio']:.2f}" if isinstance(metrics['PE Ratio'], (int, float)) and not pd.isna(metrics['PE Ratio']) else 'N/A',
            "Dividend Yield": f"{metrics['Dividend Yield']*100:.2f}%" if isinstance(metrics['Dividend Yield'], (int, float)) and not pd.isna(metrics['Dividend Yield']) else 'N/A',
            "52 Week High": format_large_number(metrics['52 Week High']),
            "52 Week Low": format_large_number(metrics['52 Week Low']),
            "Beta": f"{metrics['Beta']:.2f}" if isinstance(metrics['Beta'], (int, float)) and not pd.isna(metrics['Beta']) else 'N/A',
            "EPS": format_large_number(metrics['EPS'])
        }
        
        # Valuation status
        valuation = evaluate_stock(df)
        
        # Create price chart
        price_fig = go.Figure()
        price_fig.add_trace(go.Candlestick(
            x=df.index,
            open=df['Open'],
            high=df['High'],
            low=df['Low'],
            close=df['Close'],
            name='OHLC'
        ))
        price_fig.update_layout(
            title=f"{stock_name} Stock Price",
            yaxis_title='Stock Price (₹)',
            xaxis_title='Date',
            template='plotly_white',
            height=500
        )
        
        # Moving Averages chart
        ma_fig = go.Figure()
        ma_fig.add_trace(go.Scatter(x=df.index, y=df['Close'], mode='lines', name='Close Price'))
        
        if 'MA20' in df_with_indicators.columns:
            ma_fig.add_trace(go.Scatter(x=df_with_indicators.index, y=df_with_indicators['MA20'], mode='lines', name='20-day MA', line=dict(color='blue')))
        
        if 'MA50' in df_with_indicators.columns:
            ma_fig.add_trace(go.Scatter(x=df_with_indicators.index, y=df_with_indicators['MA50'], mode='lines', name='50-day MA', line=dict(color='orange')))
        
        if 'MA200' in df_with_indicators.columns:
            ma_fig.add_trace(go.Scatter(x=df_with_indicators.index, y=df_with_indicators['MA200'], mode='lines', name='200-day MA', line=dict(color='red')))
        
        ma_fig.update_layout(
            title="Moving Averages",
            yaxis_title='Price (₹)',
            template='plotly_white',
            height=400
        )
        
        # Bollinger Bands chart
        bb_fig = None
        if 'Upper_Band' in df_with_indicators.columns and 'Lower_Band' in df_with_indicators.columns:
            bb_fig = go.Figure()
            bb_fig.add_trace(go.Scatter(x=df.index, y=df['Close'], mode='lines', name='Close Price'))
            bb_fig.add_trace(go.Scatter(x=df_with_indicators.index, y=df_with_indicators['Upper_Band'], mode='lines', name='Upper Band', line=dict(dash='dash')))
            bb_fig.add_trace(go.Scatter(x=df_with_indicators.index, y=df_with_indicators['MA20'], mode='lines', name='20-day MA'))
            bb_fig.add_trace(go.Scatter(x=df_with_indicators.index, y=df_with_indicators['Lower_Band'], mode='lines', name='Lower Band', line=dict(dash='dash')))
            
            bb_fig.update_layout(
                title="Bollinger Bands",
                yaxis_title='Price (₹)',
                template='plotly_white',
                height=400
            )
        
        # RSI chart
        rsi_fig = None
        if 'RSI' in df_with_indicators.columns:
            rsi_fig = go.Figure()
            rsi_fig.add_trace(go.Scatter(x=df_with_indicators.index, y=df_with_indicators['RSI'], mode='lines', name='RSI'))
            
            # Add overbought/oversold lines
            rsi_fig.add_hline(y=70, line_dash="dash", line_color="red", annotation_text="Overbought")
            rsi_fig.add_hline(y=30, line_dash="dash", line_color="green", annotation_text="Oversold")
            
            rsi_fig.update_layout(
                title="Relative Strength Index (RSI)",
                yaxis_title='RSI Value',
                template='plotly_white',
                height=300
            )
        
        # MACD chart
        macd_fig = None
        if all(x in df_with_indicators.columns for x in ['MACD', 'Signal_Line', 'MACD_Histogram']):
            macd_fig = go.Figure()
            macd_fig.add_trace(go.Scatter(x=df_with_indicators.index, y=df_with_indicators['MACD'], mode='lines', name='MACD'))
            macd_fig.add_trace(go.Scatter(x=df_with_indicators.index, y=df_with_indicators['Signal_Line'], mode='lines', name='Signal Line'))
            
            # Add MACD histogram
            colors = ['red' if x < 0 else 'green' for x in df_with_indicators['MACD_Histogram']]
            macd_fig.add_trace(go.Bar(x=df_with_indicators.index, y=df_with_indicators['MACD_Histogram'], name='Histogram', marker_color=colors))
            
            macd_fig.update_layout(
                title="MACD (Moving Average Convergence Divergence)",
                yaxis_title='Value',
                template='plotly_white',
                height=300
            )
        
        # Volume chart
        volume_fig = go.Figure()
        volume_fig.add_trace(go.Bar(
            x=df.index,
            y=df['Volume'],
            name='Volume'
        ))
        
        volume_fig.update_layout(
            title=f"{stock_name} Trading Volume",
            yaxis_title='Volume',
            xaxis_title='Date',
            template='plotly_white',
            height=400
        )
        
        # Prepare metrics table
        metrics_df = pd.DataFrame.from_dict(metrics, orient='index', columns=['Value'])
        metrics_df.index.name = 'Metric'
        
        # Format dividends and splits for display
        dividends_html = "No recent dividends found"
        if not dividends.empty:
            dividends_html = dividends.to_html(index=False)
            
        splits_html = "No recent stock splits found"
        if not splits.empty:
            splits_html = splits.to_html(index=False)
        
        return {
            "company_name": info.get('longName', stock_name),
            "company_overview": company_overview,
            "metrics": formatted_metrics,
            "valuation": valuation,
            "price_chart": price_fig,
            "ma_chart": ma_fig,
            "bb_chart": bb_fig,
            "rsi_chart": rsi_fig,
            "macd_chart": macd_fig,
            "volume_chart": volume_fig,
            "metrics_table": metrics_df.to_html(),
            "dividends": dividends_html,
            "splits": splits_html,
            "historical_data": df.to_csv()
        }
    
    except Exception as e:
        return {"error": f"Error analyzing {stock_name}: {str(e)}"}

# Multi-Stock Comparison Function
def multi_stock_comparison(stock_symbols, stock_names, period, interval):
    """Compare multiple stocks side by side"""
    try:
        all_data = []
        all_metrics = []
        
        # Fetch data for all stocks
        for symbol, name in zip(stock_symbols, stock_names):
            try:
                data = get_stock_data(symbol, period, interval)
                df = data['history']
                
                if not df.empty:
                    # Add stock name as a column for identification
                    df['Stock'] = name
                    all_data.append(df)
                    
                    # Store metrics for comparison
                    metrics = data['metrics']
                    metrics['Stock'] = name
                    all_metrics.append(metrics)
            except Exception as e:
                return {"error": f"Error fetching data for {name}: {str(e)}"}
        
        if not all_data:
            return {"error": "No data available for the selected stocks."}
            
        # Combine all stock data
        combined_df = pd.concat(all_data)
        
        # Normalized price chart (for better comparison)
        normalized_df = combined_df.copy()
        
        # Group by stock and normalize the Close price
        for stock in stock_names:
            stock_data = normalized_df[normalized_df['Stock'] == stock]
            if not stock_data.empty:
                base_value = stock_data['Close'].iloc[0]
                normalized_df.loc[normalized_df['Stock'] == stock, 'Normalized'] = \
                    normalized_df.loc[normalized_df['Stock'] == stock, 'Close'] / base_value * 100
        
        # Plot normalized prices
        norm_fig = px.line(
            normalized_df, 
            x=normalized_df.index, 
            y='Normalized', 
            color='Stock',
            title="Normalized Stock Price Comparison (Base 100)"
        )
        norm_fig.update_layout(
            yaxis_title='Normalized Price (Base 100)',
            xaxis_title='Date',
            template='plotly_white',
            height=500
        )
        
        # Absolute price chart
        price_fig = px.line(
            combined_df, 
            x=combined_df.index, 
            y='Close', 
            color='Stock',
            title="Stock Price Comparison"
        )
        price_fig.update_layout(
            yaxis_title='Price (₹)',
            xaxis_title='Date',
            template='plotly_white',
            height=500
        )
        
        # Calculate returns for different periods
        returns_data = []
        
        for stock in stock_names:
            stock_data = combined_df[combined_df['Stock'] == stock]
            if len(stock_data) > 0:
                # Calculate returns
                latest_price = stock_data['Close'].iloc[-1]
                earliest_price = stock_data['Close'].iloc[0]
                total_return = ((latest_price - earliest_price) / earliest_price) * 100
                
                # Calculate volatility (standard deviation of daily returns)
                daily_returns = stock_data['Close'].pct_change().dropna()
                volatility = daily_returns.std() * 100
                
                # Add to returns data
                returns_data.append({
                    'Stock': stock,
                    'Total Return (%)': round(total_return, 2),
                    'Volatility (%)': round(volatility, 2),
                    'Max Price': round(stock_data['High'].max(), 2),
                    'Min Price': round(stock_data['Low'].min(), 2),
                    'Avg Volume': int(stock_data['Volume'].mean())
                })
        
        # Create returns dataframe
        returns_df = None
        returns_fig = None
        vol_fig = None
        if returns_data:
            returns_df = pd.DataFrame(returns_data)
            returns_df.set_index('Stock', inplace=True)
            
            # Plot returns comparison
            returns_fig = px.bar(
                returns_data,
                x='Stock',
                y='Total Return (%)',
                title="Total Return Comparison",
                color='Total Return (%)',
                color_continuous_scale='RdYlGn'
            )
            returns_fig.update_layout(
                yaxis_title='Return (%)',
                template='plotly_white',
                height=400
            )
            
            # Plot volatility comparison
            vol_fig = px.bar(
                returns_data,
                x='Stock',
                y='Volatility (%)',
                title="Volatility Comparison",
                color='Volatility (%)',
                color_continuous_scale='Viridis'
            )
            vol_fig.update_layout(
                yaxis_title='Volatility (%)',
                template='plotly_white',
                height=400
            )
        
        # Volume comparison chart
        volume_fig = px.line(
            combined_df,
            x=combined_df.index,
            y='Volume',
            color='Stock',
            title="Trading Volume Comparison"
        )
        volume_fig.update_layout(
            yaxis_title='Volume',
            xaxis_title='Date',
            template='plotly_white',
            height=500
        )
        
        # Average daily volume comparison
        avg_volumes = combined_df.groupby('Stock')['Volume'].mean().reset_index()
        avg_vol_fig = px.bar(
            avg_volumes,
            x='Stock',
            y='Volume',
            title="Average Daily Trading Volume",
            color='Volume',
            color_continuous_scale='Blues'
        )
        avg_vol_fig.update_layout(
            yaxis_title='Average Volume',
            template='plotly_white',
            height=400
        )
        
        # Financial Metrics Comparison
        metrics_comparison = None
        if all_metrics:
            # Create a metrics comparison dataframe
            metrics_df = pd.DataFrame(all_metrics)
            metrics_df.set_index('Stock', inplace=True)
            
            # Select key metrics for comparison
            key_metrics = ['Current Price', 'Market Cap', 'PE Ratio', 'Dividend Yield', 'Beta', 'EPS']
            display_metrics = metrics_df[key_metrics].copy()
            
            # Format the metrics for display
            for metric in key_metrics:
                if metric in ['Current Price', 'EPS']:
                    display_metrics[metric] = display_metrics[metric].apply(
                        lambda x: format_large_number(x) if isinstance(x, (int, float)) and not pd.isna(x) else 'N/A'
                    )
                elif metric == 'Market Cap':
                    display_metrics[metric] = display_metrics[metric].apply(
                        lambda x: format_large_number(x) if isinstance(x, (int, float)) and not pd.isna(x) else 'N/A'
                    )
                elif metric == 'Dividend Yield':
                    display_metrics[metric] = display_metrics[metric].apply(
                        lambda x: f"{x*100:.2f}%" if isinstance(x, (int, float)) and not pd.isna(x) else 'N/A'
                    )
                elif metric in ['PE Ratio', 'Beta']:
                    display_metrics[metric] = display_metrics[metric].apply(
                        lambda x: f"{x:.2f}" if isinstance(x, (int, float)) and not pd.isna(x) else 'N/A'
                    )
            
            metrics_comparison = display_metrics.to_html()
        
        return {
            "norm_price_chart": norm_fig,
            "price_chart": price_fig,
            "returns_table": returns_df.to_html() if returns_df is not None else "No returns data available",
            "returns_chart": returns_fig,
            "volatility_chart": vol_fig,
            "volume_chart": volume_fig,
            "avg_volume_chart": avg_vol_fig,
            "metrics_comparison": metrics_comparison if metrics_comparison else "No metrics data available",
            "historical_data": combined_df.to_csv()
        }
    
    except Exception as e:
        return {"error": f"Error in multi-stock comparison: {str(e)}"}

# Gradio Interface
def create_interface():
    # Get the stock database
    stocks_df = get_stock_database()
    
    # Create a dictionary of company names to symbols
    stock_options = {}
    for _, row in stocks_df.iterrows():
        stock_options[row['company_name']] = row['symbol']
    
    # Sort the stock options alphabetically
    sorted_stock_options = dict(sorted(stock_options.items()))
    
    # Define time period options
    time_options = {
        "1 Month": "1mo",
        "3 Months": "3mo",
        "6 Months": "6mo",
        "1 Year": "1y",
        "2 Years": "2y",
        "5 Years": "5y",
        "Max": "max"
    }
    
    # Define interval options
    interval_options = {
        "Daily": "1d",
        "Weekly": "1wk",
        "Monthly": "1mo"
    }
    
    # Define exchange options
    exchange_options = ["NSE", "BSE"]
    
    # Define analysis mode options
    analysis_mode_options = ["Single Stock Analysis", "Multi-Stock Comparison"]
    
    # Create the Gradio interface
    with gr.Blocks(title="Indian Stock Data Visualizer", theme=gr.themes.Soft()) as app:
        gr.Markdown("# 📈 Indian Stock Data Visualizer")
        gr.Markdown("An interactive tool for analyzing Indian stocks from NSE/BSE")
        
        with gr.Row():
            with gr.Column(scale=1):
                # Settings panel
                gr.Markdown("### ⚙️ Settings")
                exchange = gr.Radio(label="Select Exchange:", choices=exchange_options, value="NSE")
                analysis_mode = gr.Radio(label="Analysis Mode:", choices=analysis_mode_options, value="Single Stock Analysis")
                period = gr.Dropdown(label="Select Time Period:", choices=list(time_options.keys()), value="1 Year")
                interval = gr.Dropdown(label="Select Interval:", choices=list(interval_options.keys()), value="Daily")
                
                # Stock selection components
                with gr.Group(visible=True) as single_stock_group:
                    single_stock = gr.Dropdown(label="Select a Stock:", choices=list(sorted_stock_options.keys()))
                
                with gr.Group(visible=False) as multi_stock_group:
                    multi_stock = gr.Dropdown(label="Select Stocks to Compare:", choices=list(sorted_stock_options.keys()), multiselect=True)
                
                # Analysis button
                analyze_button = gr.Button("Analyze Stock(s)")
            
            # Results area
            with gr.Column(scale=3):
                # Error message box
                error_box = gr.Textbox(label="Error", visible=False)
                
                # Single stock analysis output components
                with gr.Group(visible=True) as single_stock_output:
                    company_name = gr.Textbox(label="Company Name")
                    with gr.Accordion("Company Overview", open=False):
                        company_overview = gr.Textbox()
                    
                    with gr.Row():
                        current_price = gr.Textbox(label="Current Price")
                        market_cap = gr.Textbox(label="Market Cap")
                        pe_ratio = gr.Textbox(label="P/E Ratio")
                        dividend_yield = gr.Textbox(label="Dividend Yield")
                    
                    valuation = gr.Textbox(label="Valuation Status")
                    
                    with gr.Tabs():
                        with gr.TabItem("📊 Price Chart"):
                            price_chart = gr.Plot()
                        
                        with gr.TabItem("📈 Technical Indicators"):
                            ma_chart = gr.Plot()
                            bb_chart = gr.Plot()
                            rsi_chart = gr.Plot()
                            macd_chart = gr.Plot()
                        
                        with gr.TabItem("📉 Volume"):
                            volume_chart = gr.Plot()
                        
                        with gr.TabItem("📋 Financial Data"):
                            metrics_table = gr.HTML()
                            with gr.Row():
                                with gr.Column():
                                    gr.Markdown("### Recent Dividend Declarations")
                                    dividends = gr.HTML()
                                with gr.Column():
                                    gr.Markdown("### Recent Stock Splits")
                                    splits = gr.HTML()
                            
                            download_data = gr.File(label="Download Historical Data")
                
                # Multi-stock comparison output components
                with gr.Group(visible=False) as multi_stock_output:
                    with gr.Tabs():
                        with gr.TabItem("📊 Price Comparison"):
                            gr.Markdown("### Normalized Price (Base 100)")
                            gr.Markdown("*Prices normalized to 100 at the beginning of the period for better comparison*")
                            norm_price_chart = gr.Plot()
                            
                            gr.Markdown("### Absolute Price Comparison")
                            multi_price_chart = gr.Plot()
                        
                        with gr.TabItem("📈 Performance"):
                            gr.Markdown("### Performance Metrics")
                            returns_table = gr.HTML()
                            returns_chart = gr.Plot()
                            volatility_chart = gr.Plot()
                        
                        with gr.TabItem("📉 Volume"):
                            multi_volume_chart = gr.Plot()
                            avg_volume_chart = gr.Plot()
                        
                        with gr.TabItem("📋 Metrics"):
                            metrics_comparison = gr.HTML()
                            multi_download_data = gr.File(label="Download Historical Data")
        
        # Function to toggle visibility of stock selection groups
        def toggle_stock_selection(mode):
            if mode == "Single Stock Analysis":
                return gr.update(visible=True), gr.update(visible=False)
            else:
                return gr.update(visible=False), gr.update(visible=True)
        
        # Function to toggle visibility of output groups
        def toggle_output_groups(mode):
            if mode == "Single Stock Analysis":
                return gr.update(visible=True), gr.update(visible=False)
            else:
                return gr.update(visible=False), gr.update(visible=True)
        
        # Connect the analysis mode radio button to the toggle functions
        analysis_mode.change(toggle_stock_selection, inputs=analysis_mode, outputs=[single_stock_group, multi_stock_group])
        analysis_mode.change(toggle_output_groups, inputs=analysis_mode, outputs=[single_stock_output, multi_stock_output])
        
        # Function to run the analysis
        def run_analysis(analysis_mode, exchange, period_key, interval_key, single_stock_name, multi_stock_names):
            # Clear any previous error
            error_message = ""
            
            # Get the period and interval values
            period_value = time_options[period_key]
            interval_value = interval_options[interval_key]
            
            # Set the exchange suffix
            exchange_suffix = ".NS" if exchange == "NSE" else ".BO"
            
            try:
                if analysis_mode == "Single Stock Analysis":
                    if not single_stock_name:
                        return {error_box: gr.update(value="Please select a stock", visible=True)}
                    
                    # Get the stock symbol
                    stock_symbol = stock_options[single_stock_name]
                    full_symbol = f"{stock_symbol}{exchange_suffix}"
                    
                    # Run the single stock analysis
                    result = single_stock_analysis(full_symbol, single_stock_name, period_value, interval_value)
                    
                    if "error" in result:
                        return {error_box: gr.update(value=result["error"], visible=True)}
                    
                    # Create a temporary file for download
                    import tempfile
                    temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".csv")
                    with open(temp_file.name, "w") as f:
                        f.write(result["historical_data"])
                    
                    # Update the single stock output components
                    return {
                        error_box: gr.update(visible=False),
                        company_name: result["company_name"],
                        company_overview: result["company_overview"],
                        current_price: result["metrics"]["Current Price"],
                        market_cap: result["metrics"]["Market Cap"],
                        pe_ratio: result["metrics"]["P/E Ratio"],
                        dividend_yield: result["metrics"]["Dividend Yield"],
                        valuation: result["valuation"],
                        price_chart: result["price_chart"],
                        ma_chart: result["ma_chart"],
                        bb_chart: result["bb_chart"] if result["bb_chart"] else None,
                        rsi_chart: result["rsi_chart"] if result["rsi_chart"] else None,
                        macd_chart: result["macd_chart"] if result["macd_chart"] else None,
                        volume_chart: result["volume_chart"],
                        metrics_table: result["metrics_table"],
                        dividends: result["dividends"],
                        splits: result["splits"],
                        download_data: temp_file.name
                    }
                else:  # Multi-Stock Comparison
                    if not multi_stock_names or len(multi_stock_names) < 1:
                        return {error_box: gr.update(value="Please select at least one stock", visible=True)}
                    
                    # Get the stock symbols
                    stock_symbols = [stock_options[name] for name in multi_stock_names]
                    full_symbols = [f"{symbol}{exchange_suffix}" for symbol in stock_symbols]
                    
                    # Run the multi-stock comparison
                    result = multi_stock_comparison(full_symbols, multi_stock_names, period_value, interval_value)
                    
                    if "error" in result:
                        return {error_box: gr.update(value=result["error"], visible=True)}
                    
                    # Create a temporary file for download
                    import tempfile
                    temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".csv")
                    with open(temp_file.name, "w") as f:
                        f.write(result["historical_data"])
                    
                    # Update the multi-stock output components
                    return {
                        error_box: gr.update(visible=False),
                        norm_price_chart: result["norm_price_chart"],
                        multi_price_chart: result["price_chart"],
                        returns_table: result["returns_table"],
                        returns_chart: result["returns_chart"] if "returns_chart" in result and result["returns_chart"] else None,
                        volatility_chart: result["volatility_chart"] if "volatility_chart" in result and result["volatility_chart"] else None,
                        multi_volume_chart: result["volume_chart"],
                        avg_volume_chart: result["avg_volume_chart"],
                        metrics_comparison: result["metrics_comparison"],
                        multi_download_data: temp_file.name
                    }
            except Exception as e:
                return {error_box: gr.update(value=f"An error occurred: {str(e)}", visible=True)}
        
        # Connect the analyze button to the run_analysis function
        analyze_button.click(
            run_analysis,
            inputs=[analysis_mode, exchange, period, interval, single_stock, multi_stock],
            outputs=[
                error_box,
                company_name, company_overview, current_price, market_cap, pe_ratio, dividend_yield,
                valuation, price_chart, ma_chart, bb_chart, rsi_chart, macd_chart, volume_chart,
                metrics_table, dividends, splits, download_data,
                norm_price_chart, multi_price_chart, returns_table, returns_chart, volatility_chart,
                multi_volume_chart, avg_volume_chart, metrics_comparison, multi_download_data
            ]
        )
    
    return app

# Main function
if __name__ == "__main__":
    app = create_interface()
    app.launch()